#ifndef CLIB_CLIB_BASE_BITS_H
#define CLIB_CLIB_BASE_BITS_H

#include <stddef.h>
#include "../type/clib_base_type.h"
#include "../check/clib_base_check.h"
#include "../cpu/clib_base_cpu_info.h"

/**
 * 判断数据的大小端
 */
#ifdef __BYTE_ORDER__
#   if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
#       define CLIB_WORDS_BIGENDIAN
#   endif
#endif
#if defined(MIPSEB) || defined(_MIPSEB) || defined(__MIPSEB__)
#   define CLIB_WORDS_BIGENDIAN
#endif

static size_t clib_bits_count_leading_bit0_u32_be__(clib_uint32_t x) {
    clib_check_if_true_return_value(x == 0, 32);
    size_t n = 31;
    if (x & 0xffff0000) {
        n -= 16;
        x >>= 16;
    }
    if (x & 0xff00) {
        n -= 8;
        x >>= 8;
    }
    if (x & 0xf0) {
        n -= 4;
        x >>= 4;
    }
    if (x & 0xc) {
        n -= 2;
        x >>= 2;
    }
    if (x & 0x2) { n--; }

    return n;
}

static size_t clib_bits_count_leading_bit0_u32_le__(clib_uint32_t x) {
    clib_check_if_true_return_value(x == 0, 32);
    size_t n = 31;
    if (x & 0x0000ffff) { n -= 16; } else x >>= 16;
    if (x & 0x00ff) { n -= 8; } else x >>= 8;
    if (x & 0x0f) { n -= 4; } else x >>= 4;
    if (x & 0x3) { n -= 2; } else x >>= 2;
    if (x & 0x1) { n--; }
    return n;
}

static size_t clib_bits_count_leading_bit0_u64_be__(clib_uint64_t x) {
    clib_check_if_true_return_value(x == 0, 64);
    size_t n = clib_bits_count_leading_bit0_u32_be__((clib_uint32_t) (x >> 32));
    if (n == 32) n += clib_bits_count_leading_bit0_u32_be__((clib_uint32_t) x);
    return n;
}

static size_t clib_bits_count_leading_bit0_u64_le__(clib_uint64_t x) {
    clib_check_if_true_return_value(x == 0, 64);
    size_t n = clib_bits_count_leading_bit0_u32_le__((clib_uint32_t) x);
    if (n == 32) n += clib_bits_count_leading_bit0_u32_le__((clib_uint32_t) (x >> 32));
    return n;
}

static size_t clib_bits_count_bit1_u32__(clib_uint32_t x) {
    clib_check_if_true_return_value(x == 0, 0);
    x = x - ((x >> 1) & 0x77777777) - ((x >> 2) & 0x33333333) - ((x >> 3) & 0x11111111);
    x = (x + (x >> 4)) & 0x0f0f0f0f;
    x = (x * 0x01010101) >> 24;
    return (size_t) x;
}

static size_t clib_bits_count_bit1_u64__(clib_uint64_t x) {
    clib_check_if_true_return_value(x == 0, 0);
    x = x - ((x >> 1) & 0x7777777777777777ULL) - ((x >> 2) & 0x3333333333333333ULL) -
        ((x >> 3) & 0x1111111111111111ULL);
    x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
    x = (x * 0x0101010101010101ULL) >> 56;
    return (size_t) x;
}


//统计bit为1 的个数
#define clib_bits_count_bit1_u32(x) clib_bits_count_bit1_u32__(x)
#define clib_bits_count_bit1_u64(x) clib_bits_count_bit1_u64__(x)
//统计bit为0 的个数
#define clib_bits_count_bit0_u32(x) ((x)? (size_t)clib_bits_count_bit1_u32(~(clib_uint32_t)(x)) : 32)
#define clib_bits_count_bit0_u64(x) ((x)? (size_t)clib_bits_count_bit1_u64(~(clib_uint64_t)(x)) : 64)

//统计从低位到高位，遇到第一个1之前的0的个数
#define clib_bits_count_leading_bit0_u32_be(x) clib_bits_count_leading_bit0_u32_be__(x)
#define clib_bits_count_leading_bit0_u32_le(x) clib_bits_count_leading_bit0_u32_le__(x)
#define clib_bits_count_leading_bit0_u64_be(x) clib_bits_count_leading_bit0_u64_be__(x)
#define clib_bits_count_leading_bit0_u64_le(x) clib_bits_count_leading_bit0_u64_le__(x)
//统计从低位到高位，遇到第一个0之前的1的个数
#define clib_bits_count_leading_bit1_u32_be(x) clib_bits_count_leading_bit0_u32_be__(~(clib_uint32_t)(x))
#define clib_bits_count_leading_bit1_u32_le(x) clib_bits_count_leading_bit0_u32_le__(~(clib_uint32_t)(x))
#define clib_bits_count_leading_bit1_u64_be(x) clib_bits_count_leading_bit0_u64_be__(~(clib_uint64_t)(x))
#define clib_bits_count_leading_bit1_u64_le(x) clib_bits_count_leading_bit0_u64_le__(~(clib_uint64_t)(x))


// 找到第一个值为0的bit 索引
// 如 0001 0011  第一个值为0的索引为 2
#define clib_bits_find_bit0_u32_be(x) ((x)? clib_bits_count_leading_bit0_u32_be(~(clib_uint32_t)(x)) : 0)
#define clib_bits_find_bit0_u32_le(x) ((x)? clib_bits_count_leading_bit0_u32_le(~(clib_uint32_t)(x)) : 0)
#define clib_bits_find_bit0_u64_be(x) ((x)? clib_bits_count_leading_bit0_u64_be(~(clib_uint64_t)(x)) : 0)
#define clib_bits_find_bit0_u64_le(x) ((x)? clib_bits_count_leading_bit0_u64_le(~(clib_uint64_t)(x)) : 0)
// 找到第一个值为1的bit 索引
#define clib_bits_find_bit1_u32_be(x) ((x)? clib_bits_count_leading_bit0_u32_be((clib_uint32_t)(x)) : 32)
#define clib_bits_find_bit1_u32_le(x) ((x)? clib_bits_count_leading_bit0_u32_le((clib_uint32_t)(x)) : 32)
#define clib_bits_find_bit1_u64_be(x) ((x)? clib_bits_count_leading_bit0_u64_be((clib_uint64_t)(x)) : 64)
#define clib_bits_find_bit1_u64_le(x) ((x)? clib_bits_count_leading_bit0_u64_le((clib_uint64_t)(x)) : 64)


//针对size类型 按照操作系统类型划分
#if CLIB_CPU_BIT64

#define clib_bits_count_bit0_size(x) clib_bits_count_bit0_u64(x)
#define clib_bits_count_bit1_size(x) clib_bits_count_bit1_u64(x)
#define clib_bits_count_leading_bit0_size_be(x) clib_bits_count_leading_bit0_u64_be(x)
#define clib_bits_count_leading_bit0_size_le(x) clib_bits_count_leading_bit0_u64_le(x)
#define clib_bits_count_leading_bit1_size_be(x) clib_bits_count_leading_bit1_u64_be(x)
#define clib_bits_count_leading_bit1_size_le(x) clib_bits_count_leading_bit1_u64_le(x)
#define clib_bits_find_bit0_size_be(x) clib_bits_find_bit0_u64_be(x)
#define clib_bits_find_bit0_size_le(x) clib_bits_find_bit0_u64_le(x)
#define clib_bits_find_bit1_size_be(x) clib_bits_find_bit1_u64_be(x)
#define clib_bits_find_bit1_size_le(x) clib_bits_find_bit1_u64_le(x)

#elif CLIB_CPU_BIT32

#define clib_bits_count_bit0_size(x) clib_bits_count_bit0_u32(x)
#define clib_bits_count_bit1_size(x) clib_bits_count_bit1_u32(x)
#define clib_bits_count_leading_bit0_size_be(x) clib_bits_count_leading_bit0_u32_be(x)
#define clib_bits_count_leading_bit0_size_le(x) clib_bits_count_leading_bit0_u32_le(x)
#define clib_bits_count_leading_bit1_size_be(x) clib_bits_count_leading_bit1_u32_be(x)
#define clib_bits_count_leading_bit1_size_le(x) clib_bits_count_leading_bit1_u32_le(x)
#define clib_bits_find_bit0_size_be(x) clib_bits_find_bit0_u32_be(x)
#define clib_bits_find_bit0_size_le(x) clib_bits_find_bit0_u32_le(x)
#define clib_bits_find_bit1_size_be(x) clib_bits_find_bit1_u32_be(x)
#define clib_bits_find_bit1_size_le(x) clib_bits_find_bit1_u32_le(x)

#endif


#endif //CLIB_CLIB_BASE_BITS_H
